package com.macro.mall.controller;

import com.macro.mall.common.api.CommonResult;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.sql.DataSource;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;

/**
 * 健康检查控制器
 * 提供应用健康状态检查的REST API端点
 * 
 * @author mall
 * @since 1.0
 */
@Api(tags = "HealthController", description = "应用健康检查管理")
@RestController
@RequestMapping("/health")
public class HealthController {

    private static final Logger logger = LoggerFactory.getLogger(HealthController.class);

    @Autowired
    private DataSource dataSource;

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @ApiOperation("获取应用健康状态")
    @GetMapping("/status")
    public CommonResult<Map<String, Object>> getHealthStatus() {
        Map<String, Object> healthStatus = new HashMap<>();
        
        try {
            // 基本应用信息
            Map<String, Object> appInfo = new HashMap<>();
            appInfo.put("name", "mall-admin");
            appInfo.put("version", "1.0-SNAPSHOT");
            appInfo.put("status", "UP");
            appInfo.put("timestamp", LocalDateTime.now());
            
            // 检查数据库连接
            Map<String, Object> dbStatus = checkDatabaseHealth();
            
            // 检查Redis连接
            Map<String, Object> redisStatus = checkRedisHealth();
            
            // 检查JVM状态
            Map<String, Object> jvmStatus = getJvmStatus();
            
            healthStatus.put("application", appInfo);
            healthStatus.put("database", dbStatus);
            healthStatus.put("redis", redisStatus);
            healthStatus.put("jvm", jvmStatus);
            
            // 判断整体健康状态
            boolean isHealthy = "UP".equals(dbStatus.get("status")) && 
                               "UP".equals(redisStatus.get("status"));
            
            healthStatus.put("overall", isHealthy ? "UP" : "DOWN");
            
            logger.info("健康检查完成，整体状态: {}", isHealthy ? "UP" : "DOWN");
            
            return CommonResult.success(healthStatus);
            
        } catch (Exception e) {
            logger.error("健康检查失败: {}", e.getMessage(), e);
            
            Map<String, Object> errorStatus = new HashMap<>();
            errorStatus.put("overall", "DOWN");
            errorStatus.put("error", e.getMessage());
            errorStatus.put("timestamp", LocalDateTime.now());
            
            return CommonResult.failed("健康检查失败");
        }
    }

    @ApiOperation("检查数据库连接状态")
    @GetMapping("/database")
    public CommonResult<Map<String, Object>> checkDatabase() {
        try {
            Map<String, Object> dbStatus = checkDatabaseHealth();
            return CommonResult.success(dbStatus);
        } catch (Exception e) {
            logger.error("数据库健康检查失败: {}", e.getMessage(), e);
            return CommonResult.failed("数据库连接检查失败");
        }
    }

    @ApiOperation("检查Redis连接状态")
    @GetMapping("/redis")
    public CommonResult<Map<String, Object>> checkRedis() {
        try {
            Map<String, Object> redisStatus = checkRedisHealth();
            return CommonResult.success(redisStatus);
        } catch (Exception e) {
            logger.error("Redis健康检查失败: {}", e.getMessage(), e);
            return CommonResult.failed("Redis连接检查失败");
        }
    }

    @ApiOperation("获取JVM运行状态")
    @GetMapping("/jvm")
    public CommonResult<Map<String, Object>> getJvmInfo() {
        try {
            Map<String, Object> jvmStatus = getJvmStatus();
            return CommonResult.success(jvmStatus);
        } catch (Exception e) {
            logger.error("JVM状态获取失败: {}", e.getMessage(), e);
            return CommonResult.failed("JVM状态获取失败");
        }
    }

    /**
     * 检查数据库健康状态
     */
    private Map<String, Object> checkDatabaseHealth() {
        Map<String, Object> dbStatus = new HashMap<>();
        
        try {
            JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
            long startTime = System.currentTimeMillis();
            
            // 执行简单查询
            Integer result = jdbcTemplate.queryForObject("SELECT 1", Integer.class);
            long responseTime = System.currentTimeMillis() - startTime;
            
            dbStatus.put("status", "UP");
            dbStatus.put("database", "MySQL");
            dbStatus.put("responseTime", responseTime + "ms");
            dbStatus.put("validationQuery", "SELECT 1");
            dbStatus.put("result", result);
            dbStatus.put("timestamp", LocalDateTime.now());
            
        } catch (Exception e) {
            dbStatus.put("status", "DOWN");
            dbStatus.put("database", "MySQL");
            dbStatus.put("error", e.getMessage());
            dbStatus.put("timestamp", LocalDateTime.now());
            
            logger.error("数据库连接检查失败: {}", e.getMessage());
        }
        
        return dbStatus;
    }

    /**
     * 检查Redis健康状态
     */
    private Map<String, Object> checkRedisHealth() {
        Map<String, Object> redisStatus = new HashMap<>();
        
        try {
            long startTime = System.currentTimeMillis();
            
            // 执行ping命令
            String pong = redisTemplate.getConnectionFactory()
                .getConnection()
                .ping();
            
            long responseTime = System.currentTimeMillis() - startTime;
            
            redisStatus.put("status", "UP");
            redisStatus.put("cache", "Redis");
            redisStatus.put("responseTime", responseTime + "ms");
            redisStatus.put("ping", pong);
            redisStatus.put("timestamp", LocalDateTime.now());
            
        } catch (Exception e) {
            redisStatus.put("status", "DOWN");
            redisStatus.put("cache", "Redis");
            redisStatus.put("error", e.getMessage());
            redisStatus.put("timestamp", LocalDateTime.now());
            
            logger.error("Redis连接检查失败: {}", e.getMessage());
        }
        
        return redisStatus;
    }

    /**
     * 获取JVM状态信息
     */
    private Map<String, Object> getJvmStatus() {
        Runtime runtime = Runtime.getRuntime();
        
        Map<String, Object> jvmStatus = new HashMap<>();
        
        long maxMemory = runtime.maxMemory();
        long totalMemory = runtime.totalMemory();
        long freeMemory = runtime.freeMemory();
        long usedMemory = totalMemory - freeMemory;
        
        jvmStatus.put("status", "UP");
        jvmStatus.put("javaVersion", System.getProperty("java.version"));
        jvmStatus.put("processors", runtime.availableProcessors());
        
        Map<String, Object> memory = new HashMap<>();
        memory.put("max", formatBytes(maxMemory));
        memory.put("total", formatBytes(totalMemory));
        memory.put("used", formatBytes(usedMemory));
        memory.put("free", formatBytes(freeMemory));
        memory.put("usagePercent", String.format("%.2f%%", (double) usedMemory / maxMemory * 100));
        
        jvmStatus.put("memory", memory);
        jvmStatus.put("timestamp", LocalDateTime.now());
        
        return jvmStatus;
    }

    /**
     * 格式化字节数为可读格式
     */
    private String formatBytes(long bytes) {
        if (bytes < 1024) return bytes + " B";
        if (bytes < 1024 * 1024) return String.format("%.2f KB", bytes / 1024.0);
        if (bytes < 1024 * 1024 * 1024) return String.format("%.2f MB", bytes / (1024.0 * 1024));
        return String.format("%.2f GB", bytes / (1024.0 * 1024 * 1024));
    }
}